home *** CD-ROM | disk | FTP | other *** search
- /* $Id: main.c,v 4.2 1997/04/09 01:55:32 lcs Exp $
- * $Log: main.c,v $
- * Revision 4.2 1997/04/09 01:55:32 lcs
- * Much improved error handling.
- *
- * Revision 4.1 1997/04/02 22:46:37 lcs
- * Bumped to version 4
- *
- * Revision 1.8 1997/03/27 12:11:25 lcs
- * Never mind! Bah.
- *
- * Revision 1.7 1997/03/26 13:32:43 lcs
- * Added UNIT to the template, and set taskpri to 5.
- *
- * Revision 1.6 1997/02/01 14:10:08 lcs
- * A couple of bugs fixed.
- *
- * Revision 1.5 1997/01/29 15:44:49 lcs
- * It's "finished"!
- *
- * Revision 1.4 1997/01/24 23:20:47 lcs
- * Writing seem to work too...
- *
- * Revision 1.3 1997/01/23 19:55:50 lcs
- * Added AIFF and AIFC saving.
- *
- * Revision 1.2 1997/01/21 23:56:21 lcs
- * Reading seem to work okay now.
- *
- * Revision 1.1 1997/01/17 23:34:28 lcs
- * Initial revision
- *
- */
-
- /*
- * This code is written using DICE, and is based on the DosHan example
- * source code that came with the compiler. Not all comments are mine,
- * by the way...
- *
- * Done by Martin Blom 1997. Public Domain.
- *
- */
-
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/ports.h>
- #include <exec/memory.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/filehandler.h>
- #include <dos/rdargs.h>
-
- #include <devices/ahi.h>
- #include <proto/ahi.h>
-
- #include <clib/exec_protos.h>
- #include <clib/alib_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/utility_protos.h>
-
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "main.h"
-
-
- /*
- * Prototypes
- */
-
- LONG PlayAndSwap(struct HandlerData *, LONG);
- long extended2long(extended *);
- void ulong2extended (ULONG, extended *);
- void FillAIFFheader(struct HandlerData *);
- void FillAIFCheader(struct HandlerData *);
- LONG ReadCOMMchunk(struct HandlerData *, UBYTE *, LONG);
- long AllocAudio(int);
- void FreeAudio(void);
- long ParseArgs(struct HandlerData *, char *);
- long InitHData(struct HandlerData *);
- void FreeHData(struct HandlerData *);
- void returnpacket (struct DosPacket *);
- void Initialize (void);
- void UnInitialize (void);
-
-
- /*
- * Some macros
- */
-
- #define min(a,b) ((a)<=(b)?(a):(b))
- #define DOS_TRUE -1
- #define DOS_FALSE 0
- #define BTOC(bptr) ((void *)((long)(bptr) << 2))
- #define CTOB(cptr) ((BPTR)(((long)cptr) >> 2))
-
-
- /*
- * My debug stuff....
- */
-
- #define HIT(x) {char *a=NULL; *a=x;}
- void kprintf(char *, ...);
-
-
- /*
- * Global variables
- */
-
- const static char ID[] = "$VER: AHI-Handler 4.2 (9.4.97)\r\n";
-
- struct List HanList;
- struct DeviceNode *DevNode;
- struct MsgPort *PktPort;
- int AllocCnt;
- BOOL Running;
-
- struct MsgPort *AHImp = NULL;
- struct AHIRequest *AHIio = NULL;
- BYTE AHIDevice = -1;
- struct Library *AHIBase;
-
- struct AIFCHeader AIFCHeader = {
- ID_FORM, NULL, ID_AIFC,
- ID_FVER, sizeof(FormatVersionHeader), {
- AIFCVersion1
- },
- ID_COMM, sizeof(ExtCommonChunk), {
- 0,
- 0,
- 0,
- {0},
- NO_COMPRESSION,
- sizeof("not compressed")-1,
- 'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'
- },
- ID_SSND, NULL, {0,0}
- };
-
- struct AIFFHeader AIFFHeader = {
- ID_FORM, NULL, ID_AIFF,
- ID_COMM, sizeof(CommonChunk),{
- 0,
- 0,
- 0,
- {0}
- },
- ID_SSND, NULL, {0,0}
- };
-
-
- /******************************************************************************
- **** Entry ********************************************************************
- ******************************************************************************/
-
- /*
- * Note that we use the _main entry point. Also notice that we do not
- * need to open any libraries.. they are openned for us via DICE's
- * unique auto-library-open ability.
- */
-
- void _main ()
- {
- struct DosPacket *packet;
- struct Process *proc = (struct Process *) FindTask (NULL);
-
- PktPort = &proc->pr_MsgPort;
- NewList (&HanList);
- Initialize ();
-
- Running = TRUE;
- AllocCnt = 0;
-
- #ifdef DEBUG
- kprintf("Init\n");
- #endif
-
- /*
- * Main Loop
- */
-
- while(Running) {
- struct Message *msg;
-
- while ((msg = GetMsg (PktPort)) == NULL)
- Wait (1 << PktPort->mp_SigBit);
- packet = (struct DosPacket *) msg->mn_Node.ln_Name;
-
- /*
- * default return value
- */
-
- packet->dp_Res1 = DOS_TRUE;
- packet->dp_Res2 = 0;
-
- /*
- * switch on packet
- */
-
- switch (packet->dp_Type) {
-
- case ACTION_DIE: /* ??? */
- {
- break;
- }
-
- /***********************************************************************/
-
- case ACTION_FINDUPDATE: /* FileHandle,Lock,Name Bool */
- case ACTION_FINDINPUT: /* FileHandle,Lock,Name Bool */
- case ACTION_FINDOUTPUT: /* FileHandle,Lock,Name Bool */
- {
- struct FileHandle *fh = BTOC (packet->dp_Arg1);
- unsigned char *base = BTOC (packet->dp_Arg3);
- int len = *base;
- char buf[128];
- struct HandlerData *data;
- int unit = AHI_DEFAULT_UNIT;
-
- // Skip volume name and ':'
-
- while(*++base != ':')
- --len;
- ++base;
-
- {
- // Convert /'s to blanks
-
- char *p = base;
-
- while(*++p)
- if(*p == '/')
- *p = ' ';
- }
-
- if (len >= sizeof (buf))
- len = sizeof (buf) - 1;
-
- strncpy (buf, base, len - 1);
- buf[len - 1] = '\n';
- buf[len] = 0;
-
- #ifdef DEBUG
- kprintf("ACTION_FIND#?: %s\n", (char *) buf);
- #endif
-
- data = AllocVec(sizeof(struct HandlerData), MEMF_PUBLIC | MEMF_CLEAR);
- if(! data) {
- packet->dp_Res1 = DOS_FALSE;
- packet->dp_Res2 = ERROR_NO_FREE_STORE;
- break;
- }
-
- if(packet->dp_Res2 = ParseArgs(data, (char *) buf)) {
- FreeHData(data);
- packet->dp_Res1 = DOS_FALSE;
- break;
- }
-
- if(data->args.unit) {
- unit = *data->args.unit;
- }
-
- if(packet->dp_Res2 = AllocAudio(unit)) {
- FreeAudio();
- FreeHData(data);
- packet->dp_Res1 = DOS_FALSE;
- break;
- }
-
-
- fh->fh_Arg1 = (ULONG) data;
- fh->fh_Port = (struct MsgPort *) DOS_TRUE;
- break;
- }
-
- /***********************************************************************/
-
- case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
- {
-
- /*
- * Reading is straightforward except for handling EOF... We
- * must guarentee a return value of 0 (no bytes left) before
- * beginning to return EOFs (-1's). If we return a negative
- * number right off programs like COPY will assume a failure
- * (if AUDIO: is the source) and delete the destination file.
- *
- * The basic idea is to feed the packets from one buffer while
- * recording asyncroniously to the other. When we have read
- * the buffer, we wait until the other is filled, and switch
- * buffer pointers.
- */
-
- struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
- UBYTE *dest = (void *) packet->dp_Arg2;
- LONG length, filled;
-
- #ifdef DEBUG
- kprintf("ACTION_READ: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
- #endif
-
- if(! data->initialized) {
- packet->dp_Res2 = InitHData(data);
- if(packet->dp_Res2) {
- packet->dp_Res1 = -1;
- break;
- }
- }
-
- length = filled = min(data->totallength, packet->dp_Arg3);
-
- if(length <= 0) {
- packet->dp_Res1 = length;
- data->totallength = -1;
- break;
- }
-
- if(data->buffer1 == NULL) {
-
- data->buffer1 = AllocVec(data->buffersize, MEMF_PUBLIC);
- data->buffer2 = AllocVec(data->buffersize, MEMF_PUBLIC);
- data->readreq = AllocVec(sizeof (struct AHIRequest), MEMF_PUBLIC);
-
- if((data->buffer1 == NULL)
- || (data->buffer2 == NULL)
- || (data->readreq == NULL)) {
- packet->dp_Res1 = -1;
- packet->dp_Res2 = ERROR_NO_FREE_STORE;
- break;
- }
-
- CopyMem(AHIio, data->readreq, sizeof (struct AHIRequest));
-
- // Fill buffer 2
- // Note that io_Offset is always 0 the first time
-
- data->readreq->ahir_Std.io_Command = CMD_READ;
- data->readreq->ahir_Std.io_Data = data->buffer2;
- data->readreq->ahir_Std.io_Length = data->buffersize;
- data->readreq->ahir_Std.io_Offset = 0;
- data->readreq->ahir_Type = data->type;
- data->readreq->ahir_Frequency = data->freq;
- data->readreq->ahir_Volume = data->vol;
- data->readreq->ahir_Position = data->pos;
- SendIO((struct IORequest *) data->readreq);
-
- // Force buffer switch filling of the other buffer
-
- data->length = data->offset = 0;
-
- // Check if we should write a header first
-
- if(data->format == AIFF) {
- if(length < sizeof(struct AIFFHeader)) {
- packet->dp_Res1 = -1;
- packet->dp_Res2 = ERROR_BAD_NUMBER;
- break;
- }
-
- FillAIFFheader(data);
-
- CopyMem(&AIFFHeader, dest, sizeof(struct AIFFHeader));
- dest += sizeof(struct AIFFHeader);
- length -= sizeof(struct AIFFHeader);
- }
-
- else if(data->format == AIFC) {
- if(length < sizeof(struct AIFCHeader)) {
- packet->dp_Res1 = -1;
- packet->dp_Res2 = ERROR_BAD_NUMBER;
- break;
- }
-
- FillAIFCheader(data);
-
- CopyMem(&AIFCHeader, dest, sizeof(struct AIFCHeader));
- dest += sizeof(struct AIFCHeader);
- length -= sizeof(struct AIFCHeader);
- }
- }
-
-
- while(length > 0) {
- LONG thislength;
-
- if(data->offset >= data->length) {
- void *temp;
-
- temp = data->buffer1;
- data->buffer1 = data->buffer2;
- data->buffer2 = temp;
-
- if(WaitIO((struct IORequest *) data->readreq)) {
- packet->dp_Res1 = -1;
- if(data->readreq->ahir_Std.io_Error == AHIE_HALFDUPLEX) {
- packet->dp_Res2 = ERROR_OBJECT_IN_USE;
- }
- else {
- packet->dp_Res2 = ERROR_READ_PROTECTED;
- }
- break;
- }
-
- data->length = data->readreq->ahir_Std.io_Actual;
- data->offset = 0;
-
- data->readreq->ahir_Std.io_Command = CMD_READ;
- data->readreq->ahir_Std.io_Data = data->buffer2;
- data->readreq->ahir_Std.io_Length = data->buffersize;
- data->readreq->ahir_Type = data->type;
- data->readreq->ahir_Frequency = data->freq;
- data->readreq->ahir_Volume = data->vol;
- data->readreq->ahir_Position = data->pos;
- SendIO((struct IORequest *) data->readreq);
- } /* if */
-
- thislength = min(data->length - data->offset, length);
- CopyMem(data->buffer1 + data->offset, dest, thislength);
- dest += thislength;
- length -= thislength;
- data->offset += thislength;
- data->totallength -= thislength;
- } /* while */
-
- if(packet->dp_Res2 == 0) {
- packet->dp_Res1 = filled;
- }
- break;
-
- } /* ACTION_READ */
-
- /***********************************************************************/
-
- case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
- {
- struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
- UBYTE *src = (void *) packet->dp_Arg2;
- LONG length = packet->dp_Arg3, filled;
-
- #ifdef DEBUG
- kprintf("ACTION_WRITE: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
- #endif
-
- if(data->buffer1 == NULL) {
- // Check headers?
-
- switch(data->args.format) {
- case AIFF:
- if((((ULONG *) src)[0] != ID_FORM)
- || (((ULONG *) src)[2] != ID_AIFF)) {
- packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- }
- break;
-
- case AIFC:
- if((((ULONG *) src)[0] != ID_FORM)
- || (((ULONG *) src)[2] != ID_AIFC)) {
- packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
- }
- break;
-
- case 0:
- if(((ULONG *) src)[0] == ID_FORM) {
- if(((ULONG *) src)[2] == ID_AIFF) {
- data->args.format = AIFF;
- }
- else if(((ULONG *) src)[2] == ID_AIFC) {
- data->args.format = AIFC;
- }
- }
- break;
-
- default:
- break;
- }
-
- if(packet->dp_Res2) {
- packet->dp_Res1 = -1;
- break;
- }
-
- if((data->args.format == AIFF) || (data->args.format == AIFC)) {
- LONG skiplen = 0;
-
- skiplen = ReadCOMMchunk(data, src, length);
- src += skiplen;
- length -= skiplen;
- }
-
- if(packet->dp_Res2 = InitHData(data)) {
- packet->dp_Res1 = -1;
- break;
- }
-
- data->writing = TRUE;
-
- data->buffer1 = AllocVec(data->buffersize, MEMF_PUBLIC);
- data->buffer2 = AllocVec(data->buffersize, MEMF_PUBLIC);
-
- if((data->buffer1 == NULL) || (data->buffer2 == NULL)) {
- packet->dp_Res1 = -1;
- packet->dp_Res2 = ERROR_NO_FREE_STORE;
- break;
- }
-
- data->offset = 0;
- data->length = (data->buffersize / AHI_SampleFrameSize(data->type))
- * AHI_SampleFrameSize(data->type);
-
- }
-
- length = min(data->totallength, length);
- filled = min(data->totallength, packet->dp_Arg3);
-
- while(length > 0) {
- LONG thislength;
-
- if(data->offset >= data->length) {
- packet->dp_Res2 = PlayAndSwap(data, data->length);
- if(packet->dp_Res2) {
- packet->dp_Res1 = -1;
- break;
- }
- }
-
- thislength = min(data->length - data->offset, length);
- CopyMem(src, data->buffer1 + data->offset, thislength);
- src += thislength;
- length -= thislength;
- data->offset += thislength;
- data->totallength -= thislength;
-
- } /* while */
-
- if(packet->dp_Res2 == 0) {
- packet->dp_Res1 = filled;
- }
- break;
- }
-
- /***********************************************************************/
-
- case ACTION_END: /* FHArg1 Bool:TRUE */
- {
- struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
-
- #ifdef DEBUG
- kprintf("ACTION_END\n");
- #endif
-
- // Abort any reading requests
-
- if(data->readreq) {
- AbortIO((struct IORequest *) data->readreq);
- WaitIO((struct IORequest *) data->readreq);
- }
-
- // Finish any playing requests
-
- if(data->writing) {
- PlayAndSwap(data, data->offset);
-
- if(data->writereq1) {
- WaitIO((struct IORequest *) data->writereq1);
- }
- if(data->writereq2) {
- WaitIO((struct IORequest *) data->writereq2);
- }
- }
-
- FreeHData(data);
- FreeAudio();
-
-
- break;
- }
-
- /***********************************************************************/
-
- case ACTION_IS_FILESYSTEM:
- packet->dp_Res1 = DOS_FALSE;
- break;
-
- /***********************************************************************/
-
- default:
- packet->dp_Res1 = DOS_FALSE;
- packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
- break;
-
- } /* switch */
-
- if(AllocCnt == 0)
- Running = FALSE;
-
- if (packet) {
- returnpacket (packet);
- #ifdef DEBUG
- kprintf("Retured packet\n");
- #endif
- }
-
- } /* for */
-
- #ifdef DEBUG
- kprintf("Dying..!\n");
- #endif
- UnInitialize();
- _exit (0);
- }
-
-
- /******************************************************************************
- **** PlayAndSwap **************************************************************
- ******************************************************************************/
-
- /*
- * Starts to play the current buffer. Handles double buffering.
- */
-
- LONG PlayAndSwap(struct HandlerData *data, LONG length) {
- void *temp;
-
- temp = data->buffer1;
- data->buffer1 = data->buffer2;
- data->buffer2 = temp;
-
- temp = data->writereq1;
- data->writereq1 = data->writereq2;
- data->writereq2 = temp;
-
-
- if(data->writereq1 == NULL) {
- data->writereq1 = AllocVec(sizeof (struct AHIRequest), MEMF_PUBLIC);
-
- if(data->writereq1 == NULL) {
- return ERROR_NO_FREE_STORE;
- }
-
- CopyMem(AHIio, data->writereq1, sizeof (struct AHIRequest));
- }
-
- data->offset = 0;
-
- data->writereq1->ahir_Std.io_Message.mn_Node.ln_Pri = data->priority;
- data->writereq1->ahir_Std.io_Command = CMD_WRITE;
- data->writereq1->ahir_Std.io_Data = data->buffer2;
- data->writereq1->ahir_Std.io_Length = length;
- data->writereq1->ahir_Std.io_Offset = 0;
- data->writereq1->ahir_Type = data->type;
- data->writereq1->ahir_Frequency = data->freq;
- data->writereq1->ahir_Volume = data->vol;
- data->writereq1->ahir_Position = data->pos;
- data->writereq1->ahir_Link = data->writereq2;
- SendIO((struct IORequest *) data->writereq1);
-
- if(data->writereq2) {
- if(WaitIO((struct IORequest *) data->writereq2)) {
- if(data->writereq2->ahir_Std.io_Error == AHIE_HALFDUPLEX) {
- return ERROR_OBJECT_IN_USE;
- }
- else {
- return ERROR_WRITE_PROTECTED;
- }
- }
- }
-
- return 0;
- }
-
-
- /******************************************************************************
- **** extended2long ************************************************************
- ******************************************************************************/
-
- /*
- * This function translates Apples SANE Extended used in AIFF/AIFC files
- * to a LONG. Stolen from Olaf `Olsen' Barthel's AIFF datatype.
- */
-
-
- long extended2long(extended *ex)
- {
- unsigned long mantissa;
- long exponent,sign;
-
- // We only need 32 bits precision
-
- mantissa = ex->mantissa[0];
-
- // Is the mantissa positive or negative?
-
- exponent = ex->exponent;
-
- if(exponent & 0x8000)
- sign = -1;
- else
- sign = 1;
-
- // Unbias the exponent
-
- exponent = (exponent & 0x7FFF) - 0x3FFF;
-
- // If the exponent is negative, set the mantissa to zero
-
- if(exponent < 0)
- mantissa = 0;
- else
- {
- // Special meaning?
-
- exponent -= 31;
-
- // Overflow?
-
- if(exponent > 0)
- mantissa = 0x7FFFFFFF;
- else
- mantissa >>= -exponent; // Let the point float...
- }
-
- // That's all...
-
- return(sign * (long)mantissa);
- }
-
-
- /******************************************************************************
- **** ulong2extended ***********************************************************
- ******************************************************************************/
-
- /*
- * This function translates an ULONG to Apples SANE Extended
- * used in AIFF/AIFC files.
- */
-
- void ulong2extended (ULONG in, extended *ex)
- {
- ex->exponent=31+16383;
- ex->mantissa[1]=0;
- while(!(in & 0x80000000))
- {
- ex->exponent--;
- in<<=1;
- }
- ex->mantissa[0]=in;
- }
-
-
- /******************************************************************************
- **** FillAIFFheader ***********************************************************
- ******************************************************************************/
-
- void FillAIFFheader(struct HandlerData *data) {
-
- AIFFHeader.FORMsize = sizeof(AIFFHeader) + data->totallength - 8;
- AIFFHeader.COMMchunk.numChannels = data->channels;
- AIFFHeader.COMMchunk.numSampleFrames =
- data->totallength / AHI_SampleFrameSize(data->type);
- AIFFHeader.COMMchunk.sampleSize = data->bits;
- ulong2extended(data->freq, &AIFFHeader.COMMchunk.sampleRate);
- AIFFHeader.SSNDsize = sizeof(SampledSoundHeader) + data->totallength;
- }
-
-
- /******************************************************************************
- **** FillAIFCheader ***********************************************************
- ******************************************************************************/
-
- void FillAIFCheader(struct HandlerData *data) {
-
- AIFCHeader.FORMsize = sizeof(AIFCHeader) + data->totallength - 8;
- AIFCHeader.COMMchunk.numChannels = data->channels;
- AIFCHeader.COMMchunk.numSampleFrames =
- data->totallength / AHI_SampleFrameSize(data->type);
- AIFCHeader.COMMchunk.sampleSize = data->bits;
- ulong2extended(data->freq, &AIFCHeader.COMMchunk.sampleRate);
- AIFCHeader.SSNDsize = sizeof(SampledSoundHeader) + data->totallength;
- }
-
-
- /******************************************************************************
- **** ReadCOMMchunk ************************************************************
- ******************************************************************************/
-
- LONG ReadCOMMchunk(struct HandlerData *data, UBYTE *buffer, LONG length) {
- UWORD *src = (UWORD *) buffer;
- LONG len = (length >> 1) - 2;
- ExtCommonChunk *common;
-
- while(len > 0) {
- if(((ULONG *) src)[0] == ID_COMM) {
- common = (ExtCommonChunk *) (src + 4);
- data->channels = common->numChannels;
- data->bits = common->sampleSize;
- data->totallength = common->numSampleFrames * common->numChannels *
- (data->bits <= 8 ? 1 : (data->bits <= 16 ? 2 : (data->bits <= 32 ? 4 : 0)));
- data->freq = extended2long(&common->sampleRate);
-
- if(!data->args.channels)
- data->args.channels = &data->channels;
- if(!data->args.bits)
- data->args.bits = &data->bits;
- if(!data->args.length)
- data->args.length = &data->totallength;
- if(!data->args.freq)
- data->args.freq = &data->freq;
- }
- else if(((ULONG *) src)[0] == ID_SSND) {
- src += 8;
- break;
- }
- src++;
- len--;
- }
- return (LONG) src - (LONG) buffer;
- }
-
- /******************************************************************************
- **** AllocAudio ***************************************************************
- ******************************************************************************/
-
- /*
- * If the device isn't already open, open it now
- */
-
- long AllocAudio(int unit) {
- long rc = 0;
-
- if(++AllocCnt == 1) {
- if(AHImp=CreateMsgPort()) {
- if(AHIio=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) {
- AHIio->ahir_Version = 4;
- AHIDevice=OpenDevice(AHINAME,unit,(struct IORequest *)AHIio,NULL);
- }
- }
-
- if(AHIDevice) {
- rc = ERROR_OBJECT_NOT_FOUND;
- }
- else {
- AHIBase=(struct Library *)AHIio->ahir_Std.io_Device;
- }
- }
- return rc;
- }
-
-
- /******************************************************************************
- **** FreeAudio ****************************************************************
- ******************************************************************************/
-
- /*
- * If we're the last user, close the device now
- */
-
- void FreeAudio(void)
- {
- if(--AllocCnt == 0) {
- if(AHIDevice == 0)
- CloseDevice((struct IORequest *)AHIio);
- AHIDevice = -1;
- DeleteIORequest((struct IORequest *)AHIio);
- AHIio = NULL;
- DeleteMsgPort(AHImp);
- AHImp = NULL;
- }
- }
-
-
- /******************************************************************************
- **** ParseArgs ****************************************************************
- ******************************************************************************/
-
- /*
- * Fill out argument array. Returns 0 on success, else a DOS error code.
- */
-
- long ParseArgs(struct HandlerData *data, char *initstring) {
- long rc = 0;
-
- data->rdargs = (struct RDArgs *) AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
- if(data->rdargs)
- {
- data->rdargs->RDA_Source.CS_Buffer = initstring;
- data->rdargs->RDA_Source.CS_Length = strlen(initstring);
- data->rdargs->RDA_Source.CS_CurChr = 0;
- data->rdargs->RDA_Flags |= RDAF_NOPROMPT;
-
- data->rdargs2 = ReadArgs(
- "B=BITS/K/N,C=CHANNELS/K/N,F=FREQUENCY/K/N,T=TYPE/K,V=VOLUME/K/N,P=POSITION/K/N,"
- "PRI=PRIORITY/K/N,L=LENGTH/K/N,S=SECONDS/K/N,BUF=BUFFER/K/N,UNIT/K/N",
- (LONG *) &data->args, data->rdargs);
-
- if(data->rdargs2 != NULL) {
-
-
- if(! data->args.type) {
- data->args.format = 0;
- }
- else if(Stricmp("SIGNED", data->args.type) == 0) {
- data->args.format = SIGNED;
- }
- else if(Stricmp("AIFF", data->args.type) == 0) {
- data->args.format = AIFF;
- }
- else if(Stricmp("AIFC", data->args.type) == 0) {
- data->args.format = AIFC;
- }
- else {
- rc = ERROR_BAD_TEMPLATE;
- }
- }
- else
- rc = ERROR_BAD_TEMPLATE;
-
- }
- else
- rc = ERROR_NO_FREE_STORE;
-
- return rc;
- }
-
-
- /******************************************************************************
- **** InitHData ****************************************************************
- ******************************************************************************/
-
- /*
- * Initialize the HandlerData data structure, based on the args structure
- * (see ParseArgs()). Returns 0 on success, else a DOS error code.
- */
-
- #define S8bitmode 0
- #define S16bitmode 1
- #define S32bitmode 8
-
- #define Sstereoflag 2
-
- long InitHData(struct HandlerData *data) {
- ULONG bits = 8, channels = 1, freq = 8000;
- LONG volume = 100, position = 0, priority = 0,
- length = MAXINT, buffersize = 32768;
- long rc = 0;
-
- data->initialized = TRUE;
-
- // Fill in default values
-
- if(!data->args.bits)
- data->args.bits = &bits;
- if(!data->args.channels)
- data->args.channels = &channels;
- if(!data->args.freq)
- data->args.freq = &freq;
- if(!data->args.volume)
- data->args.volume = &volume;
- if(!data->args.position)
- data->args.position = &position;
- if(!data->args.priority)
- data->args.priority = &priority;
- if(!data->args.length)
- data->args.length = &length;
- if(!data->args.buffersize)
- data->args.buffersize = &buffersize;
-
- if(!data->args.format)
- data->args.format = SIGNED;
-
- // 8, 16 or 32 bit
-
- if(*data->args.bits <= 8)
- data->type = S8bitmode;
- else if(*data->args.bits <= 16)
- data->type = S16bitmode;
- else if(*data->args.bits <= 32)
- data->type = S32bitmode;
- else {
- rc = ERROR_OBJECT_WRONG_TYPE;
- goto quit;
- }
-
- // Mono or stereo
-
- if((*data->args.channels > 2) || (*data->args.channels < 1)) {
- rc = ERROR_OBJECT_WRONG_TYPE;
- goto quit;
- }
-
- if(*data->args.channels == 2)
- data->type |= Sstereoflag;
-
- data->bits = *data->args.bits;
- data->channels = *data->args.channels;
- data->freq = *data->args.freq;
- data->vol = *data->args.volume * 0x10000 / 100;
- { // Don't ask why... :(
- LONG a;
- a = *data->args.position * 0x8000;
- a = a / 100 + 0x8000;
- data->pos = a;
- }
- data->priority = *data->args.priority;
-
- if(data->args.seconds) {
- data->totallength = *data->args.seconds * data->freq
- * AHI_SampleFrameSize(data->type);
- }
- else {
- data->totallength = (*data->args.length / AHI_SampleFrameSize(data->type))
- * AHI_SampleFrameSize(data->type);
- }
-
- data->format = data->args.format;
-
- switch(data->format) {
- case AIFF:
- case AIFC:
- data->totallength = data->totallength & ~1; // Make even
- break;
- }
-
- data->buffersize = *data->args.buffersize;
-
- quit:
- return rc;
- }
-
-
-
-
-
-
-
-
-
-
-
- /******************************************************************************
- **** FreeHData ****************************************************************
- ******************************************************************************/
-
- /*
- * Deallocate the HandlerData structure
- */
-
- void FreeHData(struct HandlerData *data) {
- if(data) {
- if(data->rdargs2)
- FreeArgs(data->rdargs2);
- if(data->rdargs);
- FreeDosObject(DOS_RDARGS, data->rdargs);
-
- FreeVec(data->buffer1);
- FreeVec(data->buffer2);
- FreeVec(data->readreq);
- FreeVec(data->writereq1);
- FreeVec(data->writereq2);
- FreeVec(data);
- }
- }
-
-
- /******************************************************************************
- **** returnpacket *************************************************************
- ******************************************************************************/
-
- /*
- * PACKET ROUTINES. Dos Packets are in a rather strange format as you
- * can see by this and how the PACKET structure is extracted in the
- * GetMsg() of the main routine.
- */
-
- void returnpacket (struct DosPacket *packet) {
- struct Message *mess;
- struct MsgPort *replyPort;
-
- replyPort = packet->dp_Port;
- mess = packet->dp_Link;
- packet->dp_Port = PktPort;
- mess->mn_Node.ln_Name = (char *) packet;
- PutMsg (replyPort, mess);
- }
-
-
- /******************************************************************************
- **** Initialize ***************************************************************
- ******************************************************************************/
-
- /*
- * During initialization DOS sends us a packet and sets our dn_SegList
- * pointer. If we set our dn_Task pointer than every Open's go to the
- * same handler (this one). If we set dn_Task to NULL, every Open()
- * will create a NEW instance of this process via the seglist, meaning
- * our process must be reentrant (i.e. -r option).
- *
- * note: dn_Task points to the MESSAGE PORT portion of the process
- * (or your own custom message port).
- *
- * If we clear the SegList then we also force DOS to reload our process
- * from disk, but we also need some way of then UnLoadSeg()ing it ourselves,
- * which we CANNOT do from this process since it rips our code out from
- * under us.
- */
-
- void Initialize () {
- struct DeviceNode *dn;
- struct Process *proc = (struct Process *) FindTask (NULL);
- struct DosPacket *packet;
-
- /*
- * Handle initial message.
- */
-
- struct Message *msg;
-
- WaitPort (PktPort);
- msg = GetMsg (PktPort);
- packet = (struct DosPacket *) msg->mn_Node.ln_Name;
-
- DevNode = dn = BTOC (packet->dp_Arg3);
- dn->dn_Task = NULL;
-
- packet->dp_Res1 = DOS_TRUE;
- packet->dp_Res2 = 0;
- returnpacket (packet);
- }
-
-
- /******************************************************************************
- **** UnInitialize *************************************************************
- ******************************************************************************/
-
- void UnInitialize (void) {
- struct DeviceNode *dn = DevNode;
-
- dn->dn_Task = NULL;
- }
-